package com.example.rpc.client;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 1.首先 Client 发送一条消息，和普通的消息相比，这条消息多了两个关键内容：
 *  一个是 correlation_id，这个表示这条消息的唯一 id，还有一个内容是 reply_to，这个表示消息回复队列的名字。
 * 2.Server 从消息发送队列获取消息并处理相应的业务逻辑，处理完成后，将处理结果发送到 reply_to 指定的回调队列中。
 * 3.Client 从回调队列中读取消息，就可以知道消息处理完后的结果了。
 *
 *
 */
@Configuration
public class RabbitConfig {

    public static final String PUBLISH_QUEUE = "publish_queue";
    public static final String REPLY_QUEUE = "reply_queue";
    public static final String EXCHANGE_NAME = "rpc_exchange_name";

    /**
     * RPC消息发送的队列
     * @return
     */
    @Bean
    Queue publishQueue() {
        return new Queue(PUBLISH_QUEUE, true, false, false);
    }

    /**
     * RPC消息返回的队列
     * @return
     */
    @Bean
    Queue replyQueue() {
        return new Queue(REPLY_QUEUE, true, false, false);
    }

    /**
     * 定义一个直连交换机
     *
     * @return
     */
    @Bean
    TopicExchange topicExchange1() {
        //1. 交换机的名称
        //2。交换机是否持久化
        //3. 如果没有与之绑定的队列，是否删除交换机
        return new TopicExchange(EXCHANGE_NAME, true, false);
    }

    /**
     * 这个定义是将交换机和队列绑定起来
     *
     * @return
     */
    @Bean
    Binding publishBinding() {
        return BindingBuilder
            //设置绑定的队列
            //表示消息的 routingkey 凡是以 “xiaomi” 开头的，都将被路由到名称为 “xiaomi” 的 Queue 上，#为通配符
            .bind(publishQueue()).to(topicExchange1()).with(PUBLISH_QUEUE);
    }

    @Bean
    Binding replyBinding() {
        return BindingBuilder
            //设置绑定的队列
            .bind(replyQueue()).to(topicExchange1()).with(REPLY_QUEUE);
    }

    /**
     * 使用 RabbitTemplate发送和接收消息
     * 并设置回调队列地址
     */
    @Bean
    RabbitTemplate restTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setReplyAddress(REPLY_QUEUE);
        rabbitTemplate.setReplyTimeout(3000);
        return rabbitTemplate;
    }

    /**
     * 给返回队列设置监听器
     */
    @Bean
    SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory) {
        SimpleMessageListenerContainer simpleMessageListenerContainer =
            new SimpleMessageListenerContainer(connectionFactory);
        simpleMessageListenerContainer.setQueueNames(REPLY_QUEUE);
        simpleMessageListenerContainer.setConnectionFactory(connectionFactory);
        simpleMessageListenerContainer.setMessageListener(restTemplate(connectionFactory));
        return simpleMessageListenerContainer;
    }
}
